#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void creare_linie(struct list **curent,char *sir);
void adaugare_pe_o_anumita_linie(struct list **curent,char *sir,long long int poz,bool ok);
struct list *search_linie(struct list *prim,long long int *poz);
void elibmem(struct list **prim);
void afisare(struct list *prim);
void stergere(struct list **curent,long long int poz,int nr_caractere,list **prim);
void inserare_linked(char *linie,long long int *poz,list **aux);

void inserare_linked(char chr,long long int *poz,struct list **prim,struct list **ultim,list **aux)
{	
	if(chr=='\n')		
	{
		adaugare_pe_o_anumita_linie(aux,"",*poz,1);
		if((*prim)==NULL)
			*prim=*aux;
		*poz=0;
		*aux=(*aux)->next;
	}
	else
	{
		char *aux_sir=(char *)malloc(sizeof(char)*2);
		aux_sir[0]=chr;
		aux_sir[1]=NULL;
		adaugare_pe_o_anumita_linie(aux,aux_sir,*poz,0);
		if(*prim==NULL)
			*prim=*aux;
		(*poz)+=1;
		free(aux_sir);
	}
}

void creare_linie(struct list **curent,char *sir)
{
	struct list *nou=(struct list *)malloc(sizeof(struct list));
	nou->linie=(char *)malloc(sizeof(char)*(strlen(sir)+1));
	strcpy(nou->linie,sir);
	nou->prev=(*curent);

	if((*curent)==NULL)			// cream prima linie din text
	{
		nou->next=nou->prev=NULL;
		(*curent)=nou;
		return ;
	}

	if((*curent)->next==NULL)		
	{
		nou->next=NULL;
		(*curent)->next=nou;
	}
	else
	{
		nou->next=(*curent)->next;
		(*curent)->next->prev=nou;
		(*curent)->next=nou;
	}
}

void adaugare_pe_o_anumita_linie(struct list **curent,char *sir,long long int poz,bool ok)
{
	char *man;
	if((*curent)==NULL)
	{
		creare_linie(&(*curent),sir);
		if(ok)
			creare_linie(curent,"");
		return;
	}

	if(poz==strlen((*curent)->linie) && strcmp(sir,"")!=0)
	{
		int lungime=strlen((*curent)->linie);
		(*curent)->linie=(char *)realloc((*curent)->linie,sizeof(char)*(lungime+2));
		(*curent)->linie[lungime]=sir[0];
		(*curent)->linie[lungime+1]=NULL;
		return;
	}

	man=(char *)malloc(sizeof(char)*(strlen((*curent)->linie)-poz+1));
	if(man==NULL)
	{
		MessageBox(NULL,"Eroare la alocarea dinamica","Eroare",MB_ICONERROR);
		return;
	}
	
	strcpy(man,(*curent)->linie+poz);
	if(ok==true)
	{
		creare_linie(&(*curent),man);
		free(man);
		//////////////////////////
		(*curent)->linie[poz]='\0';
		man=(char *)malloc(sizeof(char)*(poz+1));
		strcpy(man,(*curent)->linie);
		free((*curent)->linie);
		(*curent)->linie=(char *)malloc(sizeof(char)*(strlen(man)+strlen(sir)+1));
		///man
		strcpy((*curent)->linie,man);
		strcat((*curent)->linie,sir);
	}
	else
	{
		(*curent)->linie=(char *)realloc((*curent)->linie,sizeof(char)*(strlen((*curent)->linie)+strlen(sir)+1));
		strcpy((*curent)->linie+poz,sir);
		strcat((*curent)->linie,man);
		free(man);
	}
}

struct list *search_linie(struct list *prim,long long int *poz)
{
	//int dim=0;
	while(prim!=NULL)
	{
		if((*poz)<=(strlen(prim->linie)))
		{
			//(*poz)=dim+strlen(prim->linie)-(*poz);
			return prim;
		}
		//dim+=strlen(prim->linie);
		(*poz)=(*poz)-strlen(prim->linie)-1;
		prim=prim->next;
	}
	return NULL;
}

void elibmem(struct list **prim)
{
	struct list *p;
	while((*prim)!=NULL)
	{
		p=(*prim)->next;
		free((*prim)->linie);
		free((*prim));
		(*prim)=p;
	}
}

void stergere(struct list **curent,long long int poz,int nr_caractere,list **prim)
{
	char *aux=NULL;

	if((*curent)==NULL || nr_caractere==0)		// cazul in care nu avem ce sa mai stergem
		return ;
	struct list *urm=(*curent)->next,*ant=(*curent)->prev;		// memoram linia anterioara si linia urmatoare celei curente

	if(strlen((*curent)->linie)==0)				// cazul in care avem o linie goala
	{						// acest caz apare daca se introduc doua sau mai multe enter-uri consecutive
		if(*prim==*curent)		// adica prim este o linie goala, ce urmeaza a fi stearsa
			*prim=urm;
		nr_caractere--;				// linia curenta "reprezinta" de fapt un enter, insa nu are caractere
		free((*curent)->linie);
		free((*curent));
		if(ant!=NULL)				// se refac legaturile(se uneste linia din fata cu cea urmatoare celei curente)
			ant->next=urm;
		if(urm!=NULL)
			urm->prev=ant;
		if(nr_caractere)		// daca mai trebuie sters, se va sterge din linia urmatoare de pe pozitia 0
		{
			stergere(&urm,0,nr_caractere,prim);
			return;
		}
		else		// am terminat stergerea
			return;
	}
	if(strlen((*curent)->linie)==poz)		// cazul in care trebuie sters de la sfarsitul liniei, adica un \n
		if(urm)								// daca exista vreo linie in continuare se va uni linia curenta
		{									// cu urmatoarea si se reapeleaza functia cu ne_caractere-- (s-a sters un enter)
			aux=(char *)malloc(sizeof(char)*(strlen((*curent)->linie)+strlen(urm->linie)+1));		// concatenam liniile
			strcpy(aux,(*curent)->linie);
			strcpy(aux+strlen(aux),urm->linie);
			free((*curent)->linie);		//realocam linia curenta
			(*curent)->linie=NULL;
			(*curent)->linie=(char *)malloc(sizeof(char)*(strlen(aux)+1));
			strcpy((*curent)->linie,aux);
			(*curent)->next=urm->next;
			if(urm->next)
				urm->next->prev=(*curent);
			free(urm->linie);
			free(urm);
			if(aux)
			{
				free(aux);
				aux=NULL;
			}
			nr_caractere--;		// am sters un enter
			stergere(curent,poz,nr_caractere,prim);
			return;
		}
	if(poz+nr_caractere <= strlen((*curent)->linie))			// daca trebuie sters decat din linia curenta
	{
		if(poz+nr_caractere == strlen((*curent)->linie))	// daca trebuie sters pana la capat
			*((*curent)->linie+poz)=NULL;
		else		// mai ramane ceva dupa pozitia de sters
			strcpy((*curent)->linie+poz,(*curent)->linie+poz+nr_caractere);
		aux=(char *)malloc(sizeof(char)*(strlen((*curent)->linie)+1));
		strcpy(aux,(*curent)->linie);	
		free((*curent)->linie);			
		(*curent)->linie=NULL;
		(*curent)->linie=(char *)malloc(sizeof(char)*(strlen(aux)+1));
		strcpy((*curent)->linie,aux);
		if(aux)
		{
			free(aux);
			aux=NULL;
		}
		return ;
	}
	else			// sergerea se extinde si pe o alta linie
	{								
		nr_caractere=nr_caractere-strlen((*curent)->linie+poz);	
		if(poz==0)		// adica linia actuala trebuie stearsa in intregime
		{
			if(urm)
			{
				if(ant)		//        ana /are/ mere
				{		
					creare_linie(&ant,"");		// trebuie sa ramana doua enter-uri
					ant->next->next=urm;		// asa ca se creaza o linie goala ce reprezinta 2 enteruri consecutive
					urm->prev=ant->next;	// se refac legaturile
					if((*prim)==(*curent))		// vezi functia creare_linie()
						*prim=ant->next;	
					free((*curent)->linie);
					free((*curent));
					stergere(&(ant->next),0,nr_caractere,prim);
					return;
				}
				else	//		/are/ mere		// nu avem linie anterioara, asa ca se creaza una goala 
				{								// ce se leaga de urmatoarea celei curente, pentru a avea un enter
					creare_linie(&ant,"");
					ant->next=urm;		// se refac legaturile
					urm->prev=ant;
					if((*prim)==(*curent))
						*prim=ant;
					free((*curent)->linie);
					free((*curent));	
					stergere(&ant,0,nr_caractere,prim);
					return;
				}
			}		
		}
		else			// cazul in care trebuie sters ceva din linia curenta, insa nu tot
		{				
			*((*curent)->linie+poz)=NULL;	// de la pozitie in fata se sterge tot
											// alocam un spatiu egal cu cel ramas din linia curenta si cel din linia urmatoare
			aux=(char *)malloc(sizeof(char)*(strlen((*curent)->linie) + 1 + strlen(urm->linie)));	
			strcpy(aux,(*curent)->linie);
			strcpy(aux+strlen(aux),urm->linie);
			free((*curent)->linie);		// se concateneaza linia curenta cu cea urmatoare
			(*curent)->linie=NULL;
			(*curent)->linie=(char *)malloc(sizeof(char)*(strlen(aux)+1));
			strcpy((*curent)->linie,aux);
			(*curent)->next=urm->next;		// se refac legaturile
			if(urm->next)		
				urm->next->prev=(*curent);
			free(urm->linie);		// eliberam linia urmatoare ce am copiat-o in linia curenta
			free(urm);
			if(aux)
			{
				free(aux);
				aux=NULL;
			}
			nr_caractere--;		// mai avem un enter intre linii
			stergere(curent,poz,nr_caractere,prim);
			return;
		}
	}
	if(aux)
	{
		free(aux);
		aux=NULL;
	}
}